//异步echo服务器

#include <cstdint>
#include <utility>
#include <memory>
#include <iostream>
#include <map>
#include <boost/asio.hpp>
#include <boost/asio/io_context.hpp>

//生成唯一标识符
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

using boost::asio::ip::tcp;

class Server;


//会话类 服务器接收客户端后创建的类
class Session: public std::enable_shared_from_this<Session>
{
public:
    Session(boost::asio::io_context& ioc, Server* server = nullptr)
    :m_socket(ioc)
    ,m_data(new char[m_max_length])
    ,m_server(server) 
    {
        boost::uuids::uuid uuid = boost::uuids::random_generator()();
        m_uuid = boost::uuids::to_string(uuid);
    };

    //获取客户端套接字
    tcp::socket& Socket() { return m_socket; }

    //监听客户端的读和写事件
    void Start();

    void NewStart();

    //返回唯一标识符
    const std::string& GetUUID() { return m_uuid; }
private:
    //读事件回调 使用裸指针，可能导致程序崩溃
    void _handle_read_err(const boost::system::error_code& ec, size_t bytes);
    //写事件回调 使用裸指针，可能导致程序崩溃
    void _handle_write_err(const boost::system::error_code& ec);

    //使用智能指针解决程序崩溃问题
    void _handle_read(const boost::system::error_code& ec, size_t bytes, std::shared_ptr<Session> self_ptr);
    void _handle_write(const boost::system::error_code& ec, std::shared_ptr<Session> self_ptr);
private:
    tcp::socket m_socket; //客户端套接字
    const uint32_t m_max_length = 1024;
    std::unique_ptr<char[]> m_data;
    Server* m_server; //服务器
    std::string m_uuid; //唯一标识符
};


class Server
{
public:
    Server(boost::asio::io_context&ioc, uint16_t port);

public:

    void DeleteSession(const std::string& uuid);

private:    

    //监听客户端的连接
    void _start_accetp_err();
    //链接回调 使用裸指针，可能导致程序崩溃
    void _handle_accept_err(Session* session, const boost::system::error_code& ec);

    //使用智能指针解决程序崩溃问题
    void _start_accetp();
    void _handle_accept(std::shared_ptr<Session> session, const boost::system::error_code& ec);
private:
    boost::asio::io_context& m_ioc; //io上下文 不可以拷贝，只能引用
    tcp::acceptor m_acceptor;       //监听客户端的连接

    std::map<std::string, std::shared_ptr<Session>> m_sessions; 
};

/*
boost::asio::tcp::acceptor::async_accept() 的几种重载参数

1.async_accept 函数接受一个 boost::asio::ip::tcp::socket 对象和一个处理完成时的回调函数，
它接受一个 boost::system::error_code 参数来指示操作是否成功。（或者是一个 std::function，
或者是一个符合特定签名的函数对象）。当新的连接被接受时，socket 对象会被设置为与新连接对应的状态

2.另一个版本的 async_accept 允许指定一个 endpoint 对象，该对象将被设置为新连接的远程端点信息。
然而，需要注意的是，Boost.Asio 的标准库并不直接提供这种形式的 async_accept，你可能需要自定义
实现或使用 async_accept_some（尽管它通常用于 UDP）或 async_connect 的上下文来理解这个概念。
对于 TCP acceptor，通常不需要显式指定 endpoint，因为新的连接会自然地带来这些信息。
*/